﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using System.Windows.Media;
using System.Threading.Tasks;

using CommonBehaviors;
using CommonBehaviors.Actions;
using PetBuddy.Helpers;
using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.CommonBot.Profiles;
using Styx.CommonBot.Routines;
using Styx.TreeSharp;
using Styx.WoWInternals.WoWObjects;

using Action = Styx.TreeSharp.Action;

namespace PetBuddy
{
    public class PetBuddy : BotBase
    {
        #region Global overrides

        public readonly Version _Version = new Version(1, svn._revision);
        public override string Name { get { return "PetBuddy"; } }
        public override PulseFlags PulseFlags { get { return PulseFlags.All; } }
        public override Form ConfigurationForm { get { return new UILoader(); } }

        #endregion
        

        #region Module list

        public static PetBuddy Instance;
        public PetBuddy()
        {
            Instance = this;
        }

        #endregion


        #region Init

        public bool _startUp = true;

        public override void Initialize() {
            PetBuddySettings.UpdateSettings();

            //TODO: Check for updates

            base.Initialize();

        }

        #endregion


        #region variables

        private Composite _root;
        public static LocalPlayer Me { get { return StyxWoW.Me; } }

        private static DateTime startTime;

        [Flags]
        public enum BotRunStatusEnum
        {
            IDLE = 0,
            MOVE = 1,
            HEAL = 2,
            SEEK = 4,
            PETFIGHT = 8
        }

        static BotRunStatusEnum _flag;
        public struct BotRunStatus
        {
            public static BotRunStatusEnum flag
            {
                get { return _flag; }
                set
                {
                    dlog("BotRunStatus >> {0}", value);
                    _flag = value;
                }
            }
            public static bool HasFlag(BotRunStatusEnum flags)
            {
                return flags.HasFlag(flag);
            }
        }


        #endregion


        #region loging

        static string oldLog = string.Empty;

        static void slog(Color color, string format, params object[] args)
        {
            if (string.Format(format, args) == oldLog)
                return;
            oldLog = string.Format(format, args);
            Logging.Write(color, string.Format("{0}: {1}", Instance.Name, format), args);
        }

        public static void slog(string format, params object[] args) 
        { slog(Colors.Orange, format, args); }
        public static Action aslog(string format, params object[] args)
        { return new Action(ret => slog(format, args)); }

        public static void glog(string format, params object[] args)
        { slog(Colors.LimeGreen, format, args); }
        public static Action aglog(string format, params object[] args) 
        { return new Action(ret => glog(format, args)); }

        public static void rlog(string format, params object[] args) 
        { slog(Colors.OrangeRed, format, args); }
        public static Action arlog(string format, params object[] args) 
        { return new Action(ret => rlog(format, args)); }

        private static CapacityQueue<string> logQueue = new CapacityQueue<string>(5);

        public static void dlog(string format, params object[] args) 
        {
            if (logQueue.Contains(string.Format(format, args)) || !PetBuddySettings.Instance.debugLog) return;
            logQueue.Enqueue(string.Format(format, args));

            var oldCI = Thread.CurrentThread.CurrentCulture;
            Thread.CurrentThread.CurrentCulture = new CultureInfo("ru-RU");
            Logging.WriteDiagnostic(Colors.LightSlateGray, string.Format("{0} {1}: {2}", DateTime.Now.ToLongTimeString(), Instance.Name, format), args);
            Thread.CurrentThread.CurrentCulture = oldCI;
        }

        public static Action adlog(string format, params object[] args) 
        { return new Action(ret => dlog(format, args)); }

        #endregion


        #region Startup

        public override void Start()
        {
            slog(Name + " v" + _Version + " by ZloVreD Starting...");

            //TODO: Some Start procedures...

            startTime = DateTime.Now.ToLocalTime();
            Fighter.CombatTimer = new Stopwatch();

            svn.CheckForUpdate();

            Stabler.GenerateStableList();

            BotRunStatus.flag = BotRunStatusEnum.IDLE;
        }

        #endregion


        #region Stoping

        public override void Stop()
        {

            //TODO: Some Stop procedures...

            PetBuddySettings.SaveSettings();

            Logging.Write("\n");
            slog("######################");
            slog("Stopped after [{0}]", (DateTime.Now - startTime).ToString().Remove(8));
            slog("-------- [Statistics] --------");
            slog("Battles won: {0}", Fighter.WinsLooses.FindAll(a => a.result).Count);
            slog("Battles lost: {0}", Fighter.WinsLooses.FindAll(a => !a.result).Count);
            if (CapturedPets.Count > 0)
            {
                slog("------ [Captured Pets] ------");
                slog("- {0}", from pet in CapturedPets
                              select pet
                    );
            }
            if (LvLupStatistic.Count > 0)
            {
                slog("-------- [Pets LvLup] --------");
                foreach (var stat in LvLupStatistic)
                {
                    //if (stat.curLevel > stat.startLevel)
                    slog("- {0}  {1} > {2}", stat.Name, stat.startLevel, stat.curLevel);
                }
                slog((from pet in LvLupStatistic
                      //where pet.curLevel > pet.startLevel
                      select string.Format("- {0} {1} > {2}\n", pet.Name, pet.startLevel, pet.curLevel)
                     ).Aggregate((cur, next) => cur + next)
                    );
            }
            slog("######################");
            Logging.Write("\n");

            base.Stop();
        }

        #endregion


        #region PetStats

        public struct PetLvLstatStruct
        {
            public string petGUID;
            public string Name;
            public int startLevel;
            public int curLevel;
        }

        public static List<string> CapturedPets = new List<string>();
        public static List<PetLvLstatStruct> LvLupStatistic = new List<PetLvLstatStruct>();

        #endregion


        public override Composite Root
        {
            get
            {
                return _root ?? (_root =
                                 new PrioritySelector(

                                     #region Start Checks

                                     /* ------------- *\
                                        InGame Checks
                                     \* ------------- */
                                     new Decorator(ret => !Utils.CanAction,
                                                   new Sequence(
                                                       new ActionSetActivity("[Not in Game] Waiting..."),
                                                       new Action(ret => dlog("[Not in Game] Waiting...")),
                                                       new ActionWaitForLuaEvent("", 5)
                                                       )),

                                     /* ------------ *\
                                        Alive checks
                                     \* ------------ */
                                     new Decorator(ret => Me.IsDead || Me.IsGhost,
                                                   new Sequence(
                                                       new ActionSetActivity("[I'm dead] Let's find my boddy..."),
                                                       new Action(ret => dlog("[I'm dead] Start dead behavior")),
                                                       Bots.Grind.LevelBot.CreateDeathBehavior()
                                                       )),

                                     /* ------------------ *\
                                        OnTransport checks
                                     \* ------------------ */
                                     new Decorator(ret => Me.OnTaxi || Me.IsOnTransport,
                                                   new Sequence(
                                                       new ActionSetActivity("[Taxi] We rollin, rollin, rollin..."),
                                                       new Action(ret => dlog("[Taxi] wait till we get the point")),
                                                       new ActionWaitForLuaEvent("", 5)
                                                       )),

                                     #endregion

                                     #region Combat basics

                                     /* ------------ *\
                                        Combat Logic
                                     \* ------------ */
                                     new Decorator(ret => Me.Combat && !PetBattles.IsInBattle,
                                                   new Sequence(
                                                       new ActionSetActivity("[Combat] Defend ourselfs!"),
                                                       new Action(ret => dlog("[Combat] Start combat behavior")),
                                                       new PrioritySelector(

                                                           new Decorator(ret => RoutineManager.Current.NeedHeal,
                                                                         RoutineManager.Current.HealBehavior),

                                                           new Decorator(ret => RoutineManager.Current.NeedCombatBuffs,
                                                                         RoutineManager.Current.CombatBuffBehavior),

                                                           new Decorator(ret => Me.GotTarget && (Me.CurrentTarget.IsPetBattleCritter || Me.CurrentTarget.IsFriendly || Me.CurrentTarget.IsDead),
                                                                         new Action(ret => Me.ClearTarget())),

                                                           new Decorator(ret => Me.GotTarget && !Me.CurrentTarget.IsFriendly,
                                                                         RoutineManager.Current.CombatBehavior)
                                                           )
                                                       )),

                                     /* --------------- *\
                                        Character buffs
                                     \* --------------- */
                                     new Decorator(ret => RoutineManager.Current.NeedPreCombatBuffs && !PetBattles.IsInBattle,
                                                   RoutineManager.Current.PreCombatBuffBehavior),

                                     /* ----------- *\
                                        Rest checks
                                     \* ----------- */
                                     new Decorator(ret => RoutineManager.Current.NeedRest && !PetBattles.IsInBattle,
                                                   new Sequence(
                                                       new ActionSetActivity("[Resting] Waiting.."),
                                                       new Action(ret => dlog("[Resting] Waiting..")),
                                                       new Action(ret => RoutineManager.Current.Rest())
                                                       )),

                                     #endregion

                                     #region PetBattle

                                     /* ---------------- *\
                                        Need heal checks
                                     \* ---------------- */
                                     new Decorator(ret => Healer.BattlePetsNeedHeal() && !PetBattles.IsInBattle
                                                          && BotRunStatus.HasFlag(BotRunStatusEnum.IDLE | BotRunStatusEnum.HEAL),
                                                   new Sequence(
                                                       new Action(ret =>
                                                           {
                                                               if (BotRunStatus.flag == BotRunStatusEnum.IDLE)
                                                               {
                                                                   slog("Heal Pets");
                                                                   BotRunStatus.flag = BotRunStatusEnum.HEAL;
                                                               }
                                                               return RunStatus.Success;
                                                           }),
                                                       Healer.HealPetsBehavior()
                                                       )),

                                     /* -------------------- *\
                                        Seek reason to fight
                                     \* -------------------- */
                                     new Decorator(ret => !PetBattles.IsInBattle
                                                          && BotRunStatus.HasFlag(BotRunStatusEnum.IDLE | BotRunStatusEnum.SEEK),
                                                   new Sequence(
                                                       new Action(ret =>
                                                           {
                                                               if (BotRunStatus.flag == BotRunStatusEnum.IDLE)
                                                               {
                                                                   slog("Seeking reason to fight");
                                                                   BotRunStatus.flag = BotRunStatusEnum.SEEK;
                                                               }
                                                               return RunStatus.Success;
                                                           }),
                                                       Seeker.FightSeeker()
                                                       )),

                                     #endregion

                                     #region PetBattle InPetCombat

                                     /* ------------------ *\
                                       Pet combat routine
                                    \* ------------------ */
                                     new Decorator(ret => PetBattles.IsInBattle
                                                          && BotRunStatus.HasFlag(BotRunStatusEnum.IDLE | BotRunStatusEnum.SEEK | BotRunStatusEnum.PETFIGHT),
                                                   new Sequence(
                                                       new Action(ret =>
                                                           {
                                                               if (BotRunStatus.HasFlag(BotRunStatusEnum.IDLE | BotRunStatusEnum.SEEK))
                                                               {
                                                                   slog("Let's kick some ass");
                                                                   BotRunStatus.flag = BotRunStatusEnum.PETFIGHT;
                                                               }
                                                               return RunStatus.Success;
                                                           }),
                                                       Fighter.PetCombatBehavior()
                                                       )),

                                     #endregion

                                     new ActionAlwaysFail()

                                     ));
            }
        }

        public override void Pulse()
        {
            UpdateBotStats();
            base.Pulse();
        }

        private static void UpdateBotStats()
        {
            string status;

            if (PetBattles.IsInBattle)
                status = string.Format("[PetBattle Info] Round: {0}  InBattle: {1}",
                                       Fighter.PetBalleRound > 0 ? Fighter.PetBalleRound : 0,
                                       string.Format("{0:0}:{1:00}",
                                                     Fighter.CombatTimer.Elapsed.TotalMinutes,
                                                     Fighter.CombatTimer.Elapsed.Seconds));
            else
            {
                Fighter.IsInCombat = false;
                if (Fighter.CombatTimer.IsRunning)
                    Fighter.CombatTimer.Stop();

                var wins = Fighter.WinsLooses.FindAll(a => a.result).Count;
                var looses = Fighter.WinsLooses.FindAll(a => !a.result).Count;
                var wins_h = Fighter.WinsLooses.FindAll(a => a.result & DateTime.Now.Subtract(new TimeSpan(0, 1, 0)) < a.when).Count;
                var battle_h = Fighter.WinsLooses.FindAll(a => DateTime.Now.Subtract(new TimeSpan(0, 1, 0)) < a.when).Count;

                status = string.Format("[PetBuddy] Won: {0}  Lost: {1}  Battle/h: {2}  Wins/h: {3}  OnRoute: {4}",
                                       wins, looses, battle_h, wins_h, (DateTime.Now - startTime).ToString().Remove(8));
            }

            TreeRoot.StatusText = status;
        }
    }
}
